package com.ff.xyh.serurity.config;

import com.ff.xyh.serurity.filter.TokenAuthenticationFilter;
import com.ff.xyh.serurity.filter.TokenLoginFilter;
import com.ff.xyh.serurity.handler.TokenLogoutHandler;
import com.ff.xyh.serurity.security.MyPasswordEncoder;
import com.ff.xyh.serurity.security.TokenManager;
import com.ff.xyh.serurity.security.UnauthorizedEntryPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.Arrays;

/**
 * <p>
 * Security配置类
 * </p>
 *
 * @author qy
 * @since 2019-11-18
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class TokenWebSecurityConfig extends WebSecurityConfigurerAdapter {
    private UserDetailsService userDetailsService;
    private TokenManager tokenManager;
    private MyPasswordEncoder myPasswordEncoder;
    private RedisTemplate redisTemplate;

    @Autowired
    public TokenWebSecurityConfig(UserDetailsService userDetailsService, MyPasswordEncoder myPasswordEncoder,
                                  TokenManager tokenManager, RedisTemplate redisTemplate) {
        this.userDetailsService = userDetailsService;
        this.myPasswordEncoder = myPasswordEncoder;
        this.tokenManager = tokenManager;
        this.redisTemplate = redisTemplate;
    }

    /**
     * 授权 配置设置
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
//        配置没有权限访问的页面
        http.exceptionHandling()
                // 未授权处理类
                .authenticationEntryPoint(new UnauthorizedEntryPoint())
                .and()
                // 关闭csrf防护
                .csrf().disable()
                .authorizeRequests()
                .anyRequest().authenticated() // 限制所有请求
//                .antMatchers(HttpMethod.OPTIONS).permitAll() // 不拦截所有option的请求
                .and()
                // 添加注销功能 配置注销路径
                .logout().logoutUrl("/access/user/logout")
                // 添加注销处理类
                .addLogoutHandler(new TokenLogoutHandler(tokenManager,redisTemplate))
//                // 解决跨域
                .and()
                .cors().configurationSource(corsConfigurationSource())
                .and()
                // 添加登录拦截类
                .addFilter(new TokenLoginFilter(authenticationManager(), tokenManager, redisTemplate))
                // 添加权限拦截类
                .addFilter(new TokenAuthenticationFilter(authenticationManager(), tokenManager, redisTemplate)).httpBasic();
    }

    /**
     * 认证 密码处理
     * @param auth
     * @throws Exception
     */
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 1 将 UserDetailService 实现类注入， 使用默认 密码编码器
        auth.userDetailsService(userDetailsService).passwordEncoder(myPasswordEncoder);
    }

    /**
     * 不拦截的路径
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(
                "/api/**",
                "/swagger-resources/**",
                "/webjars/**",
//                "/**",    // 临时添加 用于所有操作
                "/v2/**",
                "/swagger-ui.html/**"
        );
    }

    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowedHeaders (Arrays.asList("*"));
        corsConfiguration.setAllowedMethods (Arrays.asList("*"));
        corsConfiguration.setAllowedOrigins (Arrays.asList ("*"));
        // 配置前端js允许访问的自定义响应头
//        corsConfiguration.addExposedHeader("newToken");
        corsConfiguration.setMaxAge (3600L);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfiguration);
        return source;

    }

}